www.gusucode.com > VC++ 编写软件自动升级服务源代码 > VC++ 编写软件自动升级服务源代码/gusucode/updater_src0.8.1.6/XHyperLink.cpp

    // XHyperLink.cpp  Version 1.0
//
// XHyperLink static control. Will open the default browser with the 
// given URL when the user clicks on the link.
//
// Copyright (C) 1997 - 1999 Chris Maunder
// All rights reserved. May not be sold for profit.
//
// Thanks to P錶 K. T鴑der for auto-size and window caption changes.
//
// "GotoURL" function by Stuart Patterson
// As seen in the August, 1997 Windows Developer's Journal.
// Copyright 1997 by Miller Freeman, Inc. All rights reserved.
// Modified by Chris Maunder to use TCHARs instead of chars.
//
// "Default hand cursor" from Paul DiLascia's Jan 1998 MSJ article.
//
// 2/29/00 -- P. Shaffer standard font mod.
//
///////////////////////////////////////////////////////////////////////////////
//
// Modified by:  Hans Dietrich
//               hdietrich2@hotmail.com
//
///////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "XHyperLink.h"
#include "atlconv.h"		// for Unicode conversion

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define TOOLTIP_ID 1

// Uncomment following line to enable error message box for URL navigation
//#define XHYPERLINK_REPORT_ERROR


#ifndef IDC_HAND
#define IDC_HAND MAKEINTRESOURCE(32649)   // From WINUSER.H
#endif

// sends message to parent when hyperlink is clicked (see SetNotifyParent())
UINT WM_XHYPERLINK_CLICKED = ::RegisterWindowMessage(_T("WM_XHYPERLINK_CLICKED"));

///////////////////////////////////////////////////////////////////////////////
// CXHyperLink

BEGIN_MESSAGE_MAP(CXHyperLink, CStatic)
	//{{AFX_MSG_MAP(CXHyperLink)
	ON_WM_CTLCOLOR_REFLECT()
	ON_WM_SETCURSOR()
	ON_WM_MOUSEMOVE()
	ON_WM_TIMER()
	ON_CONTROL_REFLECT(STN_CLICKED, OnClicked)
	ON_WM_ERASEBKGND()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

///////////////////////////////////////////////////////////////////////////////
// ctor
CXHyperLink::CXHyperLink()
{
	m_hLinkCursor     = NULL;			// No cursor as yet
	m_crLinkColour    = RGB(0,0,238);	// Blue
	m_crVisitedColour = RGB(85,26,139);	// Purple
	m_crHoverColour	  = RGB(255,0,0);	// Red
	m_bOverControl    = FALSE;			// Cursor not yet over control
	m_bVisited        = FALSE;			// Hasn't been visited yet.
	m_nUnderline      = ulHover;		// Underline the link?
	m_bAdjustToFit    = TRUE;			// Resize the window to fit the text?
	m_strURL          = _T("");
	m_nTimerID        = 100;
	m_bNotifyParent   = FALSE;			// TRUE = notify parent
	m_bIsURLEnabled   = TRUE;			// TRUE = navigate to url
	m_bToolTip        = TRUE;			// TRUE = display tooltip
	m_crBackground    = (UINT) -1;		// set to default (no bg color)
	m_bAlwaysOpenNew  = FALSE;			// TRUE = always open new browser window
}

///////////////////////////////////////////////////////////////////////////////
// dtor
CXHyperLink::~CXHyperLink()
{
	TRACE(_T("in CXHyperLink::~CXHyperLink\n"));

	if (m_hLinkCursor)
		DestroyCursor(m_hLinkCursor);
	m_hLinkCursor = NULL;
	m_UnderlineFont.DeleteObject();
	if (m_Brush.GetSafeHandle())
		m_Brush.DeleteObject();
}

/////////////////////////////////////////////////////////////////////////////
// CXHyperLink overrides

///////////////////////////////////////////////////////////////////////////////
// DestroyWindow
BOOL CXHyperLink::DestroyWindow() 
{
	KillTimer(m_nTimerID);
	return CStatic::DestroyWindow();
}

///////////////////////////////////////////////////////////////////////////////
// PreTranslateMessage
BOOL CXHyperLink::PreTranslateMessage(MSG* pMsg) 
{
	m_ToolTip.RelayEvent(pMsg);
	return CStatic::PreTranslateMessage(pMsg);
}

///////////////////////////////////////////////////////////////////////////////
// PreSubclassWindow
void CXHyperLink::PreSubclassWindow() 
{
	// We want to get mouse clicks via STN_CLICKED
	DWORD dwStyle = GetStyle();
	::SetWindowLong(GetSafeHwnd(), GWL_STYLE, dwStyle | SS_NOTIFY);
	
	// Set the URL as the window text
	if (m_strURL.IsEmpty())
		GetWindowText(m_strURL);

	// Check that the window text isn't empty. If it is, set it as the URL.
	CString strWndText;
	GetWindowText(strWndText);
	if (strWndText.IsEmpty()) 
	{
		ASSERT(!m_strURL.IsEmpty());	// Window and URL both NULL. DUH!
		SetWindowText(m_strURL);
	}

	CFont* pFont = GetFont();
	if (!pFont)
	{
		HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
		if (hFont == NULL)
			hFont = (HFONT) GetStockObject(ANSI_VAR_FONT);
		if (hFont)
			pFont = CFont::FromHandle(hFont);
	}
	ASSERT(pFont->GetSafeHandle());

	// Create the underline font
	LOGFONT lf;
	pFont->GetLogFont(&lf);
	m_StdFont.CreateFontIndirect(&lf);
	lf.lfUnderline = (BYTE) TRUE;
	m_UnderlineFont.CreateFontIndirect(&lf);

	PositionWindow();		// Adjust size of window to fit URL if necessary
	SetDefaultCursor();		// Try and load up a "hand" cursor
	SetUnderline();

	// Create the tooltip
	if (m_bToolTip)
	{
		CRect rect; 
		GetClientRect(rect);
		m_ToolTip.Create(this);
		m_ToolTip.AddTool(this, m_strURL, rect, TOOLTIP_ID);
	}

	CStatic::PreSubclassWindow();
}

/////////////////////////////////////////////////////////////////////////////
// CXHyperLink message handlers

///////////////////////////////////////////////////////////////////////////////
// OnClicked
void CXHyperLink::OnClicked()
{
	m_bOverControl = FALSE;
	int result = HINSTANCE_ERROR + 1;
	if (m_bIsURLEnabled)
		result = (int)GotoURL(m_strURL, SW_SHOW, m_bAlwaysOpenNew);
	m_bVisited = (result > HINSTANCE_ERROR);
	if (!m_bVisited)
	{
		MessageBeep(MB_ICONEXCLAMATION);	 // Unable to follow link
		ReportError(result);
	}
	else 
		SetVisited();						// Repaint to show visited colour

	NotifyParent();
}

///////////////////////////////////////////////////////////////////////////////
// CtlColor
#ifdef _DEBUG
HBRUSH CXHyperLink::CtlColor(CDC* pDC, UINT nCtlColor) 
#else
HBRUSH CXHyperLink::CtlColor(CDC* pDC, UINT /*nCtlColor*/) 
#endif
{
	ASSERT(nCtlColor == CTLCOLOR_STATIC);

	if (m_bOverControl)
		pDC->SetTextColor(m_crHoverColour);
	else if (m_bVisited)
		pDC->SetTextColor(m_crVisitedColour);
	else
		pDC->SetTextColor(m_crLinkColour);

	// transparent text.
	pDC->SetBkMode(TRANSPARENT);

	if (m_Brush.GetSafeHandle())
	{
		pDC->SetBkColor(m_crBackground);
		return (HBRUSH) m_Brush;
	}
	else
	{
		return (HBRUSH)GetStockObject(NULL_BRUSH);
	}
}

///////////////////////////////////////////////////////////////////////////////
// OnMouseMove
void CXHyperLink::OnMouseMove(UINT nFlags, CPoint point) 
{
	if (!m_bOverControl)		// Cursor has just moved over control
	{
		m_bOverControl = TRUE;

		if (m_nUnderline == ulHover)
			SetFont(&m_UnderlineFont);
		Invalidate();

		SetTimer(m_nTimerID, 100, NULL);
	}
	CStatic::OnMouseMove(nFlags, point);
}

///////////////////////////////////////////////////////////////////////////////
// OnTimer
void CXHyperLink::OnTimer(UINT nIDEvent) 
{
	CPoint p(GetMessagePos());
	ScreenToClient(&p);

	CRect rect;
	GetClientRect(rect);
	if (!rect.PtInRect(p))
	{
		m_bOverControl = FALSE;
		KillTimer(m_nTimerID);

		if (m_nUnderline != ulAlways)
			SetFont(&m_StdFont);
		rect.bottom+=10;
		InvalidateRect(rect);
	}
	
	CStatic::OnTimer(nIDEvent);
}

///////////////////////////////////////////////////////////////////////////////
// OnSetCursor
BOOL CXHyperLink::OnSetCursor(CWnd* /*pWnd*/, UINT /*nHitTest*/, UINT /*message*/) 
{
	if (m_hLinkCursor)
	{
		::SetCursor(m_hLinkCursor);
		return TRUE;
	}
	return FALSE;
}

///////////////////////////////////////////////////////////////////////////////
// OnEraseBkgnd
BOOL CXHyperLink::OnEraseBkgnd(CDC* pDC) 
{
	CRect rect;
	GetClientRect(rect);
	if (m_crBackground != (UINT)-1)
		pDC->FillSolidRect(rect, m_crBackground);
	else
		pDC->FillSolidRect(rect, ::GetSysColor(COLOR_3DFACE));

	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// CXHyperLink operations

///////////////////////////////////////////////////////////////////////////////
// SetURL
void CXHyperLink::SetURL(CString strURL)
{
	m_strURL = strURL;

	if (::IsWindow(GetSafeHwnd())) 
	{
		PositionWindow();
		m_ToolTip.UpdateTipText(strURL, this, TOOLTIP_ID);
	}
}

///////////////////////////////////////////////////////////////////////////////
// SetColours
void CXHyperLink::SetColours(COLORREF crLinkColour, 
							 COLORREF crVisitedColour,	
							 COLORREF crHoverColour /* = -1 */) 
{ 
	m_crLinkColour	= crLinkColour; 
	m_crVisitedColour = crVisitedColour;

	if (crHoverColour == -1)
		m_crHoverColour = ::GetSysColor(COLOR_HIGHLIGHT);
	else
		m_crHoverColour = crHoverColour;

	if (::IsWindow(m_hWnd))
		Invalidate(); 
}

///////////////////////////////////////////////////////////////////////////////
// SetBackgroundColour
void CXHyperLink::SetBackgroundColour(COLORREF crBackground)
{
	m_crBackground = crBackground;
	if (m_Brush.GetSafeHandle())
		m_Brush.DeleteObject();
	m_Brush.CreateSolidBrush(m_crBackground);
}

///////////////////////////////////////////////////////////////////////////////
// SetVisited
void CXHyperLink::SetVisited(BOOL bVisited /* = TRUE */) 
{ 
	m_bVisited = bVisited; 

	if (::IsWindow(GetSafeHwnd()))
		Invalidate(); 
}

///////////////////////////////////////////////////////////////////////////////
// SetLinkCursor
void CXHyperLink::SetLinkCursor(HCURSOR hCursor)
{ 
	m_hLinkCursor = hCursor;
	if (m_hLinkCursor == NULL)
		SetDefaultCursor();
}

///////////////////////////////////////////////////////////////////////////////
// SetUnderline
void CXHyperLink::SetUnderline(int nUnderline /*=ulHover*/)
{
	if (m_nUnderline == nUnderline)
		return;

	if (::IsWindow(GetSafeHwnd()))
	{
		if (nUnderline == ulAlways)
			SetFont(&m_UnderlineFont);
		else
			SetFont(&m_StdFont);

		Invalidate(); 
	}

	m_nUnderline = nUnderline;
}

///////////////////////////////////////////////////////////////////////////////
// SetAutoSize
void CXHyperLink::SetAutoSize(BOOL bAutoSize /* = TRUE */)
{
	m_bAdjustToFit = bAutoSize;

	if (::IsWindow(GetSafeHwnd()))
		PositionWindow();
}

///////////////////////////////////////////////////////////////////////////////
// SetWindowText
void CXHyperLink::SetWindowText(LPCTSTR lpszString)
{
	ASSERT(lpszString);
	if (!lpszString)
		return;
	CStatic::SetWindowText(_T(""));
	RedrawWindow();
	CStatic::SetWindowText(lpszString);
	PositionWindow();
}

///////////////////////////////////////////////////////////////////////////////
// PositionWindow

// Move and resize the window so that the window is the same size
// as the hyperlink text. This stops the hyperlink cursor being active
// when it is not directly over the text. If the text is left justified
// then the window is merely shrunk, but if it is centred or right
// justified then the window will have to be moved as well.
//
// Suggested by P錶 K. T鴑der 
//
void CXHyperLink::PositionWindow()
{
	if (!::IsWindow(GetSafeHwnd()) || !m_bAdjustToFit) 
		return;

	// Get the current window position
	CRect WndRect, ClientRect;
	GetWindowRect(WndRect);
	GetClientRect(ClientRect);

	ClientToScreen(ClientRect);

	CWnd* pParent = GetParent();
	if (pParent)
	{
		pParent->ScreenToClient(WndRect);
		pParent->ScreenToClient(ClientRect);
	}

	// Get the size of the window text
	CString strWndText;
	GetWindowText(strWndText);

	CDC* pDC = GetDC();
	CFont* pOldFont = pDC->SelectObject(&m_UnderlineFont);
	CSize Extent = pDC->GetTextExtent(strWndText);
	pDC->SelectObject(pOldFont);
	ReleaseDC(pDC);

	// Adjust for window borders
	Extent.cx += WndRect.Width() - ClientRect.Width(); 
	Extent.cy += WndRect.Height() - ClientRect.Height(); 

	// Get the text justification via the window style
	DWORD dwStyle = GetStyle();

	// Recalc the window size and position based on the text justification
	if (dwStyle & SS_CENTERIMAGE)
		WndRect.DeflateRect(0, (WndRect.Height() - Extent.cy)/2);
	else
		WndRect.bottom = WndRect.top + Extent.cy;

	if (dwStyle & SS_CENTER) 
		WndRect.DeflateRect((WndRect.Width() - Extent.cx)/2, 0);
	else if (dwStyle & SS_RIGHT) 
		WndRect.left = WndRect.right - Extent.cx;
	else // SS_LEFT = 0, so we can't test for it explicitly 
		WndRect.right = WndRect.left + Extent.cx;

	// Move the window
	SetWindowPos(NULL, 
				 WndRect.left, WndRect.top, 
				 WndRect.Width(), WndRect.Height(), 
				 SWP_NOZORDER);
}

/////////////////////////////////////////////////////////////////////////////
// CXHyperLink implementation

///////////////////////////////////////////////////////////////////////////////
// SetDefaultCursor
void CXHyperLink::SetDefaultCursor()
{
	if (m_hLinkCursor == NULL)				// No cursor handle - try to load one
	{
		// First try to load the Win98 / Windows 2000 hand cursor

		TRACE(_T("loading from IDC_HAND\n"));
		m_hLinkCursor = AfxGetApp()->LoadStandardCursor(IDC_HAND);

		if (m_hLinkCursor == NULL)			// Still no cursor handle - 
											// load the WinHelp hand cursor
		{
			// The following appeared in Paul DiLascia's Jan 1998 MSJ articles.
			// It loads a "hand" cursor from the winhlp32.exe module.

			TRACE(_T("loading from winhlp32\n"));

			// Get the windows directory
			CString strWndDir;
			GetWindowsDirectory(strWndDir.GetBuffer(MAX_PATH), MAX_PATH);
			strWndDir.ReleaseBuffer();

			strWndDir += _T("\\winhlp32.exe");

			// This retrieves cursor #106 from winhlp32.exe, which is a hand pointer
			HMODULE hModule = LoadLibrary(strWndDir);
			if (hModule) 
			{
				HCURSOR hHandCursor = ::LoadCursor(hModule, MAKEINTRESOURCE(106));
				if (hHandCursor)
					m_hLinkCursor = CopyCursor(hHandCursor);
				FreeLibrary(hModule);
			}
		}
	}
}

///////////////////////////////////////////////////////////////////////////////
// GetRegKey
LONG CXHyperLink::GetRegKey(HKEY key, LPCTSTR subkey, LPTSTR retdata)
{
	HKEY hkey;
	LONG retval = RegOpenKeyEx(key, subkey, 0, KEY_QUERY_VALUE, &hkey);

	if (retval == ERROR_SUCCESS) 
	{
		long datasize = MAX_PATH;
		TCHAR data[MAX_PATH];
		RegQueryValue(hkey, NULL, data, &datasize);
		_tcscpy(retdata, data);
		RegCloseKey(hkey);
	}

	return retval;
}

///////////////////////////////////////////////////////////////////////////////
// ReportError
void CXHyperLink::ReportError(int nError)
{
#ifdef XHYPERLINK_REPORT_ERROR

	CString str;
	switch (nError) 
	{
		case 0:							str = "The operating system is out\nof memory or resources."; break;
		case SE_ERR_PNF:				str = "The specified path was not found."; break;
		case SE_ERR_FNF:				str = "The specified file was not found."; break;
		case ERROR_BAD_FORMAT:			str = "The .EXE file is invalid\n(non-Win32 .EXE or error in .EXE image)."; break;
		case SE_ERR_ACCESSDENIED:		str = "The operating system denied\naccess to the specified file."; break;
		case SE_ERR_ASSOCINCOMPLETE:	str = "The filename association is\nincomplete or invalid."; break;
		case SE_ERR_DDEBUSY:			str = "The DDE transaction could not\nbe completed because other DDE transactions\nwere being processed."; break;
		case SE_ERR_DDEFAIL:			str = "The DDE transaction failed."; break;
		case SE_ERR_DDETIMEOUT:			str = "The DDE transaction could not\nbe completed because the request timed out."; break;
		case SE_ERR_DLLNOTFOUND:		str = "The specified dynamic-link library was not found."; break;
		case SE_ERR_NOASSOC:			str = "There is no application associated\nwith the given filename extension."; break;
		case SE_ERR_OOM:				str = "There was not enough memory to complete the operation."; break;
		case SE_ERR_SHARE:				str = "A sharing violation occurred. ";
		default:						str.Format(_T("Unknown Error (%d) occurred."), nError); break;
	}
	str = "Unable to open hyperlink:\n\n" + str;
	AfxMessageBox(str, MB_ICONEXCLAMATION | MB_OK);

#else

	UNUSED_ALWAYS(nError);

#endif	// XHYPERLINK_REPORT_ERROR
}

///////////////////////////////////////////////////////////////////////////////
// NotifyParent
void CXHyperLink::NotifyParent()
{
	if (m_bNotifyParent)
	{
		CWnd *pParent = GetParent();
		if (pParent && ::IsWindow(pParent->m_hWnd))
		{
			// wParam will contain control id
			pParent->SendMessage(WM_XHYPERLINK_CLICKED, GetDlgCtrlID());
		}
	}
}

///////////////////////////////////////////////////////////////////////////////
// GotoURL
HINSTANCE CXHyperLink::GotoURL(LPCTSTR url, int showcmd, BOOL bAlwaysOpenNew /*= FALSE*/)
{
	// if no url then this is not an internet link
	if (!url || url[0] == _T('\0'))
		return (HINSTANCE) HINSTANCE_ERROR + 1;

	TCHAR key[MAX_PATH*2];

	// First try ShellExecute()
	TCHAR *verb = _T("open");
	if (bAlwaysOpenNew)
		verb = _T("new");
	HINSTANCE result = ShellExecute(NULL, verb, url, NULL,NULL, showcmd);

	// If it failed, get the .htm regkey and lookup the program
	if ((UINT)result <= HINSTANCE_ERROR) 
	{
		if (GetRegKey(HKEY_CLASSES_ROOT, _T(".htm"), key) == ERROR_SUCCESS) 
		{
			_tcscat(key, _T("\\shell\\open\\command"));

			if (GetRegKey(HKEY_CLASSES_ROOT,key,key) == ERROR_SUCCESS) 
			{
				TCHAR *pos;
				pos = _tcsstr(key, _T("\"%1\""));
				if (pos == NULL) 
				{					// No quotes found
					pos = _tcsstr(key, _T("%1"));	// Check for %1, without quotes 
					if (pos == NULL)				// No parameter at all...
						pos = key + _tcslen(key)-1;
					else
						*pos = _T('\0');				// Remove the parameter
				}
				else
				{
					*pos = _T('\0');					// Remove the parameter
				}

				_tcscat(pos, _T(" "));
				_tcscat(pos, url);

				USES_CONVERSION;
				result = (HINSTANCE) WinExec(T2A(key),showcmd);
			}
		}
	}

	return result;
}